<?php

/**
 * Description of RequestUri
 * Parsing the URI: /abc/def/ghi, and forming an array: array('abc', 'def', 'ghi')
 *
 * @author Ian Clarence <ian.clarence@gmail.com>
 */
class RequestUri {

    /**
     * The instance of this class.
     *
     * @var RequestUri
     */
    private static $instance;

    /**
     * The array of components of the URI.
     *
     * @var array
     */
    private $pageSequence = array();

    /**
     * The page number when pagination is used.
     *
     * @var int
     */
    private $pageNumber = 1;

    /**
     * The article id number if viewing a single article in the content panel.
     *
     * @var int
     */
    private $articleId;
    
    /**
     * The "pseudo-file", e.g. script.js or style.css.
     * 
     * @var string
     */
    private $pseudoFile;
    
    /**
     * The AJAX function, if appropriate.
     * 
     * @var string
     */
    private $ajaxFunction;
    
    /**
     * The Id of the subdomain.
     * 
     * @var int
     */
    private $subdomain;

    /**
     * The constructor.
     * If $allowNumeric is FALSE, then do not allow URL components to be numeric, 
     * but if a numeric component is found, set the page number to it.
     * e.g. abc/def/34 - page number = 34.
     *
     * @param bool $allowNumeric
     */
    private function __construct($allowNumeric = TRUE) {
        $requestUri = $_SERVER['REQUEST_URI'];
        $session = System::getSession();
        
        /**
         * Separating any $_GET parameters. 
         */
        $components = explode('?', $requestUri);
        if (isset($components[1])) {
            $getParams = explode('&', $components[1]);
            if (count($getParams) > 0) {
                foreach ($getParams as $getParam) {
                    list($key, $value) = explode('=', $getParam);
                    $_REQUEST[$key] = $value;
                }
            }
        }
        
        /**
         * Parsing REQUEST_URI. 
         */
        $parts = explode('/', $components[0]);
        array_shift($parts);
        $this->pageSequence = array();

        /**
         * For a multilingual site, testing the first element of pageSequence to see if it matches a language code.
         *
         */
        if (Registry::getVal('MULTILINGUAL_SITE') == 1) {
            $languages = Language::search($parts[0], 'code', FALSE, TRUE);
            
            /**
             * If it does, then that element is removed from the pageSequence.
             */
            if (is_array($languages) && count($languages) == 1) {
                $session->setVariable('LANGUAGE', $languages[0]->getFields());
                array_shift($parts);
            }

            /**
             * If not, then the default language is assumed.
             */
            else {
                
                $deflangarr = Language::search(Registry::getVal('DEFAULT_LANGUAGE'), 'code', FALSE, TRUE);
                if (is_array($deflangarr) && count($deflangarr) == 1) {
                    $session->setVariable('LANGUAGE', $deflangarr[0]->getFields());
                }
                
            }
        }

        /**
         * Looping over the remaining elements in the pageSequence.
         */
        foreach ($parts as $part) {

            /**
             * It's forgiving: in case you have too many slashes /abc//def/ghi
             */
            if ($part == '') {
            }

            /**
             * Normal components may or may not not be numeric, depending on $allowNumeric.
             * If they are not allowed, then numeric components may be used for page numbers in pagination.
             */
            else if (!$allowNumeric && is_numeric($part)) {
                $this->pageNumber = (int) round($part);
            }

            /**
             * In pagination, the page number NNNN can also be represented by component PAGINATION_PREFIX . NNNN in the URL.
             */
            else if (strpos($part, PAGINATION_PREFIX) !== FALSE) {
                $pageNumber = substr($part, strlen(PAGINATION_PREFIX));
                if (is_numeric($pageNumber)) {
                    $this->pageNumber = (int) round($pageNumber);
                }
            }

            /**
             * If viewing a single article, the article id will be represented by ARTICLE_PREFIX . NNNN in the URL.
             */
            else if (strpos($part, ARTICLE_PREFIX) !== FALSE) {
                $articleId = substr($part, strlen(ARTICLE_PREFIX));
                if (is_numeric($articleId)) {
                    $this->articleId = (int) round($articleId);
                }
            }

            /**
             * If the site has an affiliate program, the affiliate id will be represented by AFFILIATE_ID_PREFIX . NNNN in the URL.
             */
            else if (strpos($part, AFFILIATE_ID_PREFIX) !== FALSE && HAS_AFFILIATE_PROGRAM == YES) {
                $affiliateId = substr($part, strlen(AFFILIATE_ID_PREFIX));
                if (is_numeric($affiliateId)) {
                    $session->setVariable('affiliate_id', (int) round($affiliateId));
                }
            }
            
            /**
             * Separating the 'pseudo filename': i.e. any part which has a dot: e.g. style.css, ajax.php, etc. 
             */
            else if (strpos($part, '.') !== FALSE) {
                $this->pseudoFile = $part;
            }
            
            /**
             * Otherwise build the array. 
             */
            else {
                $this->pseudoFile = DEFAULT_FILENAME;
                $this->pageSequence[] = $part;                
            }
            
        }
        
    }

    /**
     * The singleton method.
     *
     * @return RequestUri
     */
    public static function getInstance() {
        if (!isset(self::$instance)) {
            $class = __CLASS__;
            self::$instance = new $class;
        }
        return self::$instance;
    }

    /**
     * Preventing users from cloning the instance.
     */
    public function __clone() {
        trigger_error('Cannot clone a singleton.', E_USER_ERROR);
    }

    /**
     * Returning the page sequence array.
     *
     * @return array
     */
    public function getPageSequence() {
        return $this->pageSequence;
    }

    /**
     * Returning the current page URL identifier.
     *
     * @return string
     */
    public function getPageUrlIdentifier() {
        $count = count($this->pageSequence);
        if ($count == 0) {
            return NULL;
        }
        return $this->pageSequence[$count - 1];
    }

    /**
     * Returning the current page object.
     *
     * @return Page
     */
    public function getPage($class) {
        $myPage = new $class;
        return $myPage->getPage($this->getPageUrlIdentifier());
    }

    /**
     * Returning the page number, when pagination is used (otherwise always 1).
     * 
     * @return int
     */
    public function getPageNumber() {
        return $this->pageNumber ? $this->pageNumber : FALSE;
    }

    /**
     * Returning the article id number, when appropriate.
     *
     * @return int
     */
    public function getArticleId() {
        return $this->articleId ? $this->articleId : FALSE;
    }

    /**
     * Returning the pseudo-file
     *
     * @return string
     */
    public function getPseudoFile() {
        return $this->pseudoFile ? $this->pseudoFile : DEFAULT_FILENAME;
    }

    /**
     * Returning the AJAX function name, when appropriate.
     *
     * @return string
     */
    public function getAjaxFunction() {
        return $this->ajaxFunction ? $this->ajaxFunction : FALSE;
    }

}
